#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

int main() {
    LLVMContext context;
    Module module("test", context);

    // Create the main function
    FunctionType *funcType = FunctionType::get(Type::getVoidTy(context), {Type::getInt32Ty(context)}, false);
    Function *myFunc = Function::Create(funcType, Function::ExternalLinkage, "myFunction", &module);
    BasicBlock *entry = BasicBlock::Create(context, "entry", myFunc);

    // Create an IRBuilder
    IRBuilder<> builder(entry);

    // Create a simple loop with n iterations
    Argument *arg = &*myFunc->arg_begin();
    arg->setName("n");
    Value *sum = builder.getInt32(0);
    BasicBlock *loopBlock = BasicBlock::Create(context, "loop", myFunc);
    BasicBlock *afterLoopBlock = BasicBlock::Create(context, "afterloop", myFunc);

    builder.CreateBr(loopBlock);
    builder.SetInsertPoint(loopBlock);
    PHINode *phi = builder.CreatePHI(Type::getInt32Ty(context), 2);
    phi->addIncoming(sum, entry);
    Value *index = phi;
    sum = builder.CreateAdd(sum, index);
    Value *nextIndex = builder.CreateAdd(index, builder.getInt32(1));
    phi->addIncoming(nextIndex, loopBlock);
    Value *loopCond = builder.CreateICmpSLT(nextIndex, arg);
    builder.CreateCondBr(loopCond, loopBlock, afterLoopBlock);

    builder.SetInsertPoint(afterLoopBlock);
    builder.CreateRetVoid();

    // Verify the module
    verifyModule(module, &errs());

    // Print the unoptimized LLVM IR
    module.print(outs(), nullptr);

    return 0;
}
